/**
* @author Ashish Gupta
* CVSSP, University of Surrey
* Copyright (c) 2010 Ashish Gupta
* All rights reserved.
*/
/**
 * 
 */
package genetic;

import hash.Cell;
import hash.CellSpace;
import image.ImageSet;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;

import configuration.GenePoolConfiguration;

import classification.VisualCodebook;

/**
 * @author Ashish
 *
 */
public class Chromosome implements GeneticInterface{
	private ArrayList<Gene> genes = null;
	private GeneMap geneMap = null;
	private VisualCodebook visualCodebook = null;
	private Double fitness = null;
	

	/**
	 * @param geneConfig
	 * @param cellSpace 
	 * @param imageSet 
	 * @return void
	 *  Chromosome Constructor during spawning population
	 */
	public Chromosome(GenePoolConfiguration geneConfig, CellSpace cellSpace, ImageSet imageSet) {
		this.visualCodebook = new VisualCodebook(geneConfig.getNumGenes(), imageSet.getImageList().getImageNames().size());
		this.geneMap = new GeneMap();
		 this.genes = new ArrayList<Gene>();
		 Iterator<Cell> cellItr = cellSpace.getCells().iterator();
		 Random rnd = new Random();
		 int numGenes = geneConfig.getNumGenes();
		 while(cellItr.hasNext()){
			 int key = cellItr.next().getCellIdx();
			 int value = rnd.nextInt(numGenes);
			 this.geneMap.put(key, value);
		 }
//		 this.visualCodebook.setCodebook(imageSet, geneConfig);
		 this.visualCodebook = chromosome2codebook(geneConfig, cellSpace, imageSet);
		 this.visualCodebook.calcPositiveHistogram(geneConfig);
		 this.visualCodebook.calcNegativeHistogram(geneConfig);
		 this.calcFitness();
	}

	/**
	 * default chromosome constructor
	 */
	public Chromosome() {
		 this.genes = new ArrayList<Gene>();
		 this.geneMap = new GeneMap();
		 this.visualCodebook = null;
		 this.fitness = null;
	}

	/**
	 * @param geneConfig 
	 * @param next
	 * Chromosome constuctor during evolution
	 */
	public Chromosome(Chromosome oldChromosome, GenePoolConfiguration geneConfig, CellSpace cellSpace, ImageSet imageSet) {
		this.genes = new ArrayList<Gene>();
		GeneticOperator geneOp = new PointMutation();
		this.geneMap = (GeneMap) geneOp.operate(oldChromosome.geneMap, geneConfig);
		this.visualCodebook = chromosome2codebook(geneConfig, cellSpace, imageSet);
		this.visualCodebook.calcPositiveHistogram(geneConfig);
		this.visualCodebook.calcNegativeHistogram(geneConfig);
		this.calcFitness();
	}

	/**
	 * @return the fitness
	 */
	public Double getFitness() {
		return this.fitness;
	}
	
	public void calcFitness(){
		FitnessFunction fitnessfunction = new BhattacharyaMetric();
		this.fitness = fitnessfunction.calcFitness(this.visualCodebook);
	}

	/**
	 * @param genes the genes to set
	 */
	public void setGenes(ArrayList<Gene> genes) {
		this.genes = genes;
	}

	/**
	 * @return the genes
	 */
	public ArrayList<Gene> getGenes() {
		return genes;
	}

	/**
	 * @param geneMap the geneMap to set
	 */
	public void setGeneMap(GeneMap geneMap) {
		this.geneMap = geneMap;
	}

	/**
	 * @return the geneMap
	 */
	public GeneMap getGeneMap() {
		return geneMap;
	}


	/* (non-Javadoc)
	 * @see genetic.GeneticInterface#chromosome2codebook()
	 */
	@Override
	public VisualCodebook chromosome2codebook(GenePoolConfiguration geneConfig, CellSpace cellSpace, ImageSet imageSet) {
		VisualCodebook visualCodebook = new VisualCodebook(geneConfig.getNumGenes(), (Integer)imageSet.getImageList().getImageNames().size());
		for(int i = 0;i < geneMap.keys().size();i++){
			int cellIdx = geneMap.getKey(i);
			int geneIdx = geneMap.get(cellIdx);
			int numFeatureVectors = cellSpace.getCells().get(cellIdx).getFeatureVectorIdentities().size();
			for(int j = 0; j < numFeatureVectors; j++){
				 int imageIdx = cellSpace.getCells().get(i).getFeatureVectorIdentities().get(j).getImageIdx();
				 visualCodebook.incrementCodebook(imageIdx, geneIdx);
			}
		}
		return visualCodebook;		
	}

	/**
	 * @param visualCodebook the visualCodebook to set
	 */
	public void setVisualCodebook(VisualCodebook visualCodebook) {
		this.visualCodebook = visualCodebook;
	}

	/**
	 * @return the visualCodebook
	 */
	public VisualCodebook getVisualCodebook() {
		return visualCodebook;
	}

}
